package vendalenger.port;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

import vendalenger.debvi.Debvi;

public class Console implements Runnable {

	private static BufferedReader br;
	private static int clears = 0;
	public static JFrame consoleWindow;
	public static JTextArea jta;

	/**
	 * Clear the console window. Make sure that the console window is already
	 * initialized.
	 */
	public static void clear() {
		clears++;
		jta.setText("FluffyConsole for Debvi " + Debvi.getDebviVersion()
				+ "\nClear#: " + clears + " \n \\> For help, see ^help \n");
	}

	/**
	 * Hide the console window. Make sure that the console window is already
	 * initialized.
	 */
	public static void hideConsole() {
		consoleWindow.setVisible(false);
	}

	/**
	 * Initialize the console window. Call this method before anything else.
	 * 
	 * @param width
	 *            Width of the window in pixels.
	 * @param height
	 *            Height of the window in pixels.
	 */
	public static void initConsole(int width, int height) {
		consoleWindow = new JFrame();
		jta = new JTextArea() {
			private static final long serialVersionUID = 1L;

			@Override
			public void paintComponent(Graphics g) {// Disable anti aliasing
				Graphics2D g2 = (Graphics2D) g;
				g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
						RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
				g2.setRenderingHint(RenderingHints.KEY_RENDERING,
						RenderingHints.VALUE_RENDER_QUALITY);
				super.paintComponent(g2);
			}
		};
		final JTextField input = new JTextField();

		consoleWindow.getContentPane().setLayout(new BorderLayout());
		consoleWindow.setResizable(true);
		consoleWindow.setPreferredSize(new Dimension(width, height));
		consoleWindow.setSize(new Dimension(width, height));
		consoleWindow.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		consoleWindow.setVisible(false);
		consoleWindow.setTitle("Debvi " + Debvi.getDebviVersion()
				+ " - Console");
		consoleWindow.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				hideConsole();
			}
		});
		BufferedImage logo = new BufferedImage(32, 32,
				BufferedImage.TYPE_4BYTE_ABGR); // Paint the three square
												// Vendalenger logo with hollow
												// insides.
		Graphics g = logo.getGraphics();
		g.setColor(Color.green);
		g.drawRect(0, 10, 10, 10);
		g.drawRect(10, 20, 10, 10);
		g.drawRect(20, 0, 10, 10);
		g.dispose();
		consoleWindow.setIconImage(logo);
		jta.setEditable(false);
		jta.setBorder(BorderFactory.createLineBorder(Color.black, 0));
		try {
			InputStream fis = Console.class
					.getResourceAsStream("terminusbold.ttf");
			Font font = Font.createFont(Font.TRUETYPE_FONT, fis);
			jta.setFont(font.deriveFont(12f));
		} catch (FontFormatException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		jta.setForeground(Color.green);
		jta.setBackground(new Color(0.05f, 0.05f, 0.05f));

		final JScrollPane jsp = new JScrollPane(jta);
		jsp.setBorder(BorderFactory.createLineBorder(Color.black, 1));

		input.setBorder(BorderFactory.createLineBorder(Color.black, 1));
		input.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
		input.setForeground(Color.green);
		input.setBackground(new Color(0.05f, 0.05f, 0.05f));
		input.setText("^");
		input.addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					System.out.println("> " + input.getText());
					Command.issue(input.getText());
					input.setText("^");
				}
			}

			@Override
			public void keyReleased(KeyEvent e) {
			}

			@Override
			public void keyTyped(KeyEvent e) {
			}
		});

		consoleWindow.add(input, BorderLayout.SOUTH);
		consoleWindow.add(jsp, BorderLayout.CENTER);

		JMenuBar mb = new JMenuBar();
		JMenu jm = new JMenu("Console");
		JMenuItem loadScript = new JMenuItem("Load .fcis");
		jm.add(loadScript);
		mb.add(jm);
		consoleWindow.setJMenuBar(mb);

		PipedOutputStream pos = new PipedOutputStream();
		System.setErr(new PrintStream(pos, true));
		System.setOut(new PrintStream(pos, true));
		br = null;
		try {
			PipedInputStream pis = new PipedInputStream(pos);
			br = new BufferedReader(new InputStreamReader(pis));
		} catch (IOException e) {
			e.printStackTrace();
			JOptionPane.showMessageDialog(null,
					"Failed to initialize console screen");
		}
		Thread t = new Thread(new Console());
		t.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Show the console window. Make sure that the console window is already
	 * initialized.
	 */
	public static void showConsole() {
		consoleWindow.setVisible(true);
	}

	/**
	 * Cause an error by trying to connect to port 235325 which does not exist.
	 */
	public static void testError() {
		try {
			new Socket("", 235325);
		} catch (UnknownHostException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * Toggle the visibility of the console window. Make sure that the console
	 * window is already initialized.
	 */
	public static void toggleConsole() {
		if (consoleWindow.isVisible()) {
			consoleWindow.setVisible(false);
		} else {
			consoleWindow.setVisible(true);
		}
	}

	@Override
	public void run() {// Start listening to System.out and append text to jta.
		String line = null;
		try {
			while ((line = br.readLine()) != null) {
				jta.append(line + "\n");
				jta.setCaretPosition(jta.getDocument().getLength());
			}
		} catch (IOException e) { // Restart when console pipe breaks.
			System.out.println("Minor error: The console pipe broke!");
			System.out.println("This is not related to any other error above.");
			System.out.println("Fluffy console is restarting...");
			run();
		}
	}
}
